// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

#nullable enable

using System;
using System.Text.Json.Serialization;
using NuGet.Shared;
using NuGet.Versioning;

namespace NuGet.Protocol.Model
{
    /// <summary>A class that represents one known vulnerability of a package.</summary>
    public sealed class PackageVulnerabilityInfo : IEquatable<PackageVulnerabilityInfo>
    {
        /// <summary>A URL to a CVE or another web page where more information about the vulnerability can be found.</summary>
        [JsonPropertyName(JsonProperties.Url)]
        public Uri Url { get; }

        /// <summary>The severity of the vulnerability</summary>
        [JsonPropertyName(JsonProperties.Severity)]
        public PackageVulnerabilitySeverity Severity { get; }

        /// <summary>Which package versions are affected by this vulnerability.</summary>
        [JsonPropertyName(JsonProperties.Versions)]
        public VersionRange Versions { get; }

        /// <summary>Creates an instance of the class</summary>
        /// <param name="url">The value for <see cref="Url"/></param>
        /// <param name="severity">The value for <see cref="Severity"/></param>
        /// <param name="versions">The value for <see cref="Versions"/></param>
        /// <exception cref="ArgumentNullException"></exception>
        [JsonConstructor]
        public PackageVulnerabilityInfo(Uri url, PackageVulnerabilitySeverity severity, VersionRange versions)
        {
            Url = url ?? throw new ArgumentNullException(paramName: nameof(url));
            Severity = severity;
            Versions = versions ?? throw new ArgumentNullException(nameof(versions));
        }

        /// <inheritdoc cref="IEquatable{T}.Equals(T?)"/>
        public bool Equals(PackageVulnerabilityInfo? other)
        {
            if (other is null)
            {
                return false;
            }

            bool equals =
                Url == other.Url &&
                Severity == other.Severity &&
                Versions.Equals(other.Versions);
            return equals;
        }

        /// <inheritdoc cref="object.Equals(object?)"/>
        public override bool Equals(object? obj) => Equals(obj as PackageVulnerabilityInfo);

        /// <inheritdoc cref="object.GetHashCode"/>
        public override int GetHashCode()
        {
            var hashCode = new HashCodeCombiner();
            hashCode.AddObject(Url.OriginalString);
            hashCode.AddObject((int)Severity);
            hashCode.AddObject(Versions);
            return hashCode.CombinedHash;
        }
    }
}
